package main.java.DMDE.controllers;

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

import main.java.DMDE.controllers.listeners.IEntityEventListener;
import main.java.DMDE.infrastructure.IProjectContext;
import main.java.DMDE.model.Class;
import main.java.DMDE.model.Method;
import main.java.DMDE.model.Attribute;
import main.java.DMDE.model.Modifier;
import main.java.DMDE.model.Visibility;
import main.java.DMDE.view.IClassView;
import main.java.DMDE.controllers.IAttributeController;
import main.java.DMDE.controllers.factories.IAttributeControllerFactory;
import main.java.DMDE.controllers.factories.IOperationControllerFactory;


public class ClassController extends BaseController implements IClassController {

    private IClassView classView;
    private Class pendingClass;
    private List<IEntityEventListener> listeners;
    private Operations operation;
    private IAttributeControllerFactory attributeControllerFactory;
    private IAttributeController attributeController;
    private IOperationControllerFactory operationControllerFactory;
    private IOperationController operationController;

    public ClassController(IProjectContext projectContext,
	    IAttributeControllerFactory attributeControllerFactory,
	    IOperationControllerFactory operationControllerFactory,
	    IClassView classView) {
	super(projectContext);
	this.classView = classView;
	this.classView.setController(this);
	this.listeners = new ArrayList<IEntityEventListener>();
	this.pendingClass = new Class("", UUID.randomUUID());
	this.operation = Operations.None;
	this.attributeControllerFactory = attributeControllerFactory;
	this.operationControllerFactory = operationControllerFactory;
    }

    @Override
    public void addSubscriber(IEntityEventListener listener) {
	this.listeners.add(listener);
    }

    @Override
    public void create(String entityName) {
	this.attributeController = this.attributeControllerFactory.create();
	this.operationController = this.operationControllerFactory.create();
	this.pendingClass.setName(entityName);
	this.classView.setClassName(entityName);
	this.classView.addAttributeView(attributeController.getAttributeView());
	this.classView.addOperationView(operationController.getOperationView());
	this.classView.showView();
	this.operation = Operations.Creating;
    }

    @Override
    public void create(Class entity) {
	this.pendingClass = entity;
	this.attributeController = this.attributeControllerFactory.create();
	this.operationController = this.operationControllerFactory.create();
	List<Attribute> attributes = this.pendingClass.getAttributes();
	List<Method> operations = this.pendingClass.getMethods();
	this.attributeController.setAttributes(attributes);
	this.operationController.setOperations(operations);
	this.classView.addAttributeView(attributeController.getAttributeView());
	this.classView.addOperationView(operationController.getOperationView());
	this.classView.setClassName(this.pendingClass.getName());
	this.classView.setVisibility(this.pendingClass.getVisibility());
	this.classView.setModifiers(this.pendingClass.getModifiers());
	this.classView.setModeUpdating();
	this.classView.showView();
	this.operation = Operations.Updating;
    }
    
    private enum Operations {
	Creating, Updating, None
    }

    @Override
    public boolean addClass() {
	String className = this.classView.getClassName();
	if (this.operation == Operations.Creating){
	    List<Attribute> attributes = this.attributeController.getAttributes();
	    this.pendingClass.setAttributes(attributes);
	    List<Method> methods = this.operationController.getMethods();
	    this.pendingClass.setMethods(methods);
	    Visibility classVisibility = classView.getVisibility();
	    List<Modifier> modifiers = classView.getModifiers();
	    pendingClass.setVisibility(classVisibility);
	    if (!modifiers.isEmpty())
		pendingClass.setModifiers(modifiers);

	    for (IEntityEventListener listener : this.listeners) {
		if(!listener.validateClassName(className))
		    return false;
	    }
	}    
	this.pendingClass.setName(className);
	
	for (IEntityEventListener listener : this.listeners) {
	    listener.handleCreatedEvent(pendingClass);
	}
	return true;
    }
   
}
